Plan Mode 的困惑与价值#
我频繁使用 Claude Code 来处理日常开发任务,很快发现了一个困惑的现象:
有时候,我说"帮我实现用户认证功能",Claude Code 会先进入一个"Plan Mode",探索代码结构、生成实现方案,等我确认后才开始执行。但有时候,同样的需求描述,它却直接开始写代码,但是结果质量不尽如人意,浪费了不少 Token 和时间。
这种不一致性让我开始思考:Claude Code 到底是如何决定什么时候该先规划、什么时候直接执行的?我能不能主动控制这个流程?
经过一段时间的摸索和实践,我逐渐理解了 Claude Code 的工作流程决策机制,也找到了一些引导它的有效方法。
Claude Code 的决策流程:何时规划 vs 直接执行#
决策逻辑:任务复杂度评估#
Claude Code 在接到任务时,会进行快速的复杂度评估,决定是 直接执行 还是进入 Plan Mode:
用户需求
↓
任务复杂度评估
- 是否涉及多个文件?
- 是否需要多步骤操作?
- 是否有多种实现方案?
- 是否可能影响现有功能?
↓
简单任务 → 直接执行
复杂任务 → 进入 Plan Mode场景分类与判断标准#
直接执行的场景:
- 微调整:修改文案、添加依赖、删除文件
- 单一操作:单个函数修改、配置文件调整
容易产生歧义的场景:
- 中等复杂度任务:添加功能(可能涉及多文件)、修复 Bug、小范围重构
- 建议:明确要求先规划,避免方向错误
建议规划的场景:
- 复杂任务:认证系统、架构重构、数据迁移、性能优化
- 多文件协调:涉及 3 个以上文件修改
- 数据相关:数据库迁移、API 接口变更
为什么会出现"应该规划却直接执行"?#
主要原因是系统默认倾向于直接执行(体现效率)、对复杂任务的判断可能不够准确、以及用户描述模糊导致被误解。解决方法是在复杂任务时明确要求先规划。
为什么需要 Plan Mode:从上下文工程看规划的必要性#
在前面我们讨论了"何时规划 vs 直接执行"的决策逻辑,但还有一个更深层的问题:为什么 Claude Code 要专门设计一个独立的 Plan Mode?
问题 1:上下文漂移导致的规划失效#
在一次对话中,随着交互的进行,LLM 的注意力焦点会不断变化。这种变化如果不加控制,就会导致早期的规划被逐渐"遗忘"。
在直接执行模式下,随着实现的深入,注意力会从原始需求逐渐转移到代码错误、依赖问题、测试调试等细节上。原始规划中的"还需要更新文档"等后续步骤容易被遗漏。
Plan Mode 通过文件持久化和上下文隔离解决这个问题:
- 规划阶段:专注于规划,生成完整的实现步骤并保存为 plan.md 文件
- 执行阶段:plan.md 内容始终在上下文顶部,即使注意力在调试,规划仍清晰可见
核心差异:Plan Mode 确保规划不会被实现细节淹没。
问题 2:方向错误的成本累积#
在规划阶段发现方向问题的成本,远低于执行后返工的成本。
没有 Plan Mode 的风险:可能写了几十行代码后,才发现方向不对(比如数据库 schema 还没更新、现有系统需要保留等),导致返工。
有 Plan Mode 的优势:Explore Agent 在规划阶段就能发现潜在问题,用户可以提前审查和调整方案,避免浪费时间和 Token。
问题 3:复杂依赖的心智负担#
复杂任务往往涉及多个步骤和依赖关系。人类和 LLM 都有工作记忆限制,难以同时记住所有依赖细节。
Plan Mode 的解决方案:
- 在规划阶段识别所有依赖关系
- 按依赖顺序排列步骤
- 明确标注每步的前置条件和输出
执行阶段只需关注当前步骤,plan 文件清晰记录了依赖关系,无需记忆所有细节。
核心优势:将依赖关系外化为文档,降低心智负担。
为什么需要独立的 Plan Mode#
Plan Mode 通过独立的规划阶段和文件持久化,从三个层面解决上下文管理问题:规划专注于"做什么"而 plan 文件始终保持在执行时的上下文顶部(上下文隔离)、在规划阶段就能发现方向问题避免返工(降低试错成本)、将依赖关系显式化为文档(管理复杂度)。
这是上下文架构层面的设计,而不仅仅是"规划 vs 不规划"的区别。
Plan Mode 的完整工作流程:五个阶段的深度解析#
当 Claude Code 决定进入 Plan Mode 后,会执行一套完整的工作流程,确保方案的合理性和可行性。
Phase 1:初始理解(Initial Understanding)#
目标:理解需求 + 探索代码库结构
核心机制:
- 最多启动 3 个 Explore Agent 并行探索
- 每个 Agent 负责不同的探索方向
- 只探索相关内容,避免读取整个代码库
Explore Agent 通过 Glob 查找文件模式、Grep 搜索关键词、Read 读取关键文件的方式,高效探索代码库,最后输出包含代码结构理解、相关文件清单和技术栈分析的报告。
Phase 2:设计(Design)#
目标:基于探索结果,设计实现方案
核心机制:
- 启动 1 个 Plan Agent
- 基于探索结果进行方案设计
- 考虑依赖关系和实现顺序
Plan Agent 会输出包含技术选择、实现步骤、文件清单的设计方案,为后续实现提供明确的指导。
Phase 3:审查(Review)#
目标:确保方案合理,发现潜在问题
核心机制:
- 读取关键文件验证假设
- 与用户确认有歧义的部分
- 使用 AskUserQuestion 获取决策
审查的四个维度:
- 逻辑正确性:检查步骤依赖是否成立、前置假设是否验证
- 技术可行性:检查技术栈兼容性、现有代码兼容性
- 安全性评估:检查常见安全风险(SQL 注入、XSS、权限漏洞、密码安全等)
- 资源约束:评估 Token 成本、执行时间、性能影响
具体审查内容:
逻辑正确性审查:步骤 B 依赖步骤 A 的输出时,确认 A 确实会产生 B 需要的结果;涉及数据库操作时,验证 schema 是否已存在;使用第三方库时,确认项目中已安装。
技术可行性审查:新功能使用的技术栈要与项目现有技术一致(如项目用 TypeScript 不要建议写 JavaScript);API 调用方式要符合现有代码风格(如项目用 axios 不要突然用 fetch);框架版本要兼容(读取 package.json 确认版本)。
安全性审查:用户输入是否经过验证和清理、密码是否正确加密存储(bcrypt、不要明文)、API 是否有适当的权限验证、SQL 查询是否使用参数化避免注入、敏感信息是否避免暴露在日志或响应中。
资源约束评估:预估单个步骤需要的上下文 token 数(避免超过 10K)、执行时间评估(单步应 < 5 分钟)、性能影响评估(大量数据操作、循环查询等需要注意)。
假设验证策略:
不是所有假设都需要验证,关键是识别出哪些假设如果错误会导致整个方案失败。
- 高优先级验证:影响后续所有步骤的假设(如数据模型定义、技术栈依赖等)必须读取文件确认
- 低优先级验证:标准技术实现和通用代码模式可以基于经验推断,执行时再调整
用户交互时机:
发现多种实现方案时询问用户偏好、发现技术约束时询问是否需要调整方案、需要业务决策时获取具体参数和配置、发现破坏性变更时确认是否继续。提问时要说明发现的问题或背景、提供的选项以及每个选项的影响。
Phase 4:最终计划(Final Plan)#
目标:生成可执行的计划文档
输出位置:.claude/plans/xxx.md
计划编写的三个核心原则:
- 可执行性:每个步骤要足够具体,明确文件路径和操作内容
- 可验证性:每个步骤完成后,能够通过明确的标准验证是否成功
- 详细程度适中:不要过于详细(失去灵活性),也不要过于简略(难以执行)
步骤颗粒度的判断标准:
单一职责原则(一个步骤只做一件事)、可独立验证(步骤完成后能单独验证结果)、执行时间控制(每个步骤执行时间应 < 5 分钟)、Token 成本控制(每个步骤需要的上下文应 < 10K tokens)。
计划应包含概述、技术选择、实现步骤(文件、操作、验收标准、依赖关系)和待确认问题。
对比示例:添加用户认证功能
糟糕的计划(过于简略,难以执行):
1. 创建 User 模型
2. 实现登录功能
3. 添加权限验证
4. 更新前端页面好的计划(可执行、可验证):
## 步骤 1:创建 User 数据模型
- 文件:`src/models/User.ts`
- 操作:定义 User 接口,包含 id、email、passwordHash、role 字段
- 验证:TypeScript 编译通过,类型定义完整
## 步骤 2:实现用户注册 API
- 文件:`src/api/auth/register.ts`
- 操作:创建 POST /api/auth/register 端点,接收 email 和 password,使用 bcrypt 加密密码后存入数据库
- 依赖:步骤 1 完成
- 验证:使用 Postman 测试注册成功,数据库中密码已加密
## 步骤 3:实现用户登录 API
- 文件:`src/api/auth/login.ts`
- 操作:创建 POST /api/auth/login 端点,验证密码后生成 JWT token(有效期 7 天)
- 依赖:步骤 2 完成
- 验证:登录成功返回 token,错误密码返回 401
## 步骤 4:实现权限验证中间件
- 文件:`src/middleware/auth.ts`
- 操作:创建 requireAuth 中间件,验证 JWT token 并将 user 信息注入 req.user
- 依赖:步骤 3 完成
- 验证:未授权访问返回 401,有效 token 通过验证关键差异:好的计划明确了文件路径、具体操作内容、验证标准和依赖关系,执行时不需要额外思考"该怎么做"。
Phase 5:退出 Plan Mode#
工具:ExitPlanMode
等待用户确认:是否执行计划
退出后的执行机制#
退出 Plan Mode 后,Claude Code 有一套完整的执行流程:
- 读取 plan.md 文件,加载到上下文顶部
- 确认执行范围(全部/部分/分阶段)
- 逐步执行:当前步骤 → 完成 → 验证 → 下一步
- plan.md 始终在上下文中,不会被实现细节淹没
关键特点:逐步提取信息、自动进度追踪、持续与 plan 交互。
执行过程中的调整策略#
轻微调整(如文件路径调整):在对话中说明,继续执行,计划保持不变。
中等调整(如需要新增步骤):暂停当前步骤,说明原因,询问用户是否调整计划或继续执行。
重大调整(如前置假设不成立):立即停止,说明问题和影响,建议重新进入 Plan Mode。
执行失败的处理#
轻微失败(语法错误、类型错误):自动修复,继续执行。
中等失败(逻辑错误、测试失败):分析原因,询问用户(修复后继续/跳过/暂停)。
严重失败(方向错误、假设不成立):停止执行,建议重新规划,等待用户决策。
验证机制#
- 自动验证:语法检查、基础功能验证(不需要用户介入)
- 半自动验证:测试运行、集成验证(可能需要用户确认)
- 手动验证:功能测试、UI 验证、性能测试(需要用户操作)
执行完成后的总结:包含完成步骤数、文件变更、测试结果、验证建议和优化建议。
Explore Agent 的高效探索机制#
为什么需要 Explore Agent?
传统做法(Read 所有文件)会消耗大量 Token 并导致信息过载。Explore Agent 通过 Glob 查找文件模式、Grep 搜索关键词、Read 关键部分的方式,实现精确定位和智能筛选。
探索策略:
- 关键词扩展:从核心词扩展到相关词(如:payment → billing, checkout, transaction)
- 文件名模式:直接模式(payment_)+ 间接模式(_order, _subscription_)
- 代码搜索优先级:类型定义 → 服务层 → API 层 → 配置文件
工作示例:探索支付功能
用户需求:"添加支付功能"
Explore Agent 的探索过程:
第 1 步:文件名探索
- Glob: **/*payment* → 找到 PaymentService.ts
- Glob: **/*billing* → 找到 BillingController.ts
- Glob: **/*order* → 找到 Order.ts, OrderService.ts
第 2 步:代码关键词搜索
- Grep: "payment" → 在 Order.ts 中发现 paymentStatus 字段
- Grep: "stripe|paypal" → 未找到,说明尚未集成支付服务
- Grep: "interface.*Payment" → 找到 PaymentMethod 接口定义
第 3 步:读取关键文件
- Read: Order.ts → 了解订单数据结构,发现 totalAmount 字段
- Read: PaymentMethod 接口 → 了解现有支付方式定义
- Read: package.json → 确认项目使用 TypeScript + Express
输出报告:
- 代码结构:订单系统已存在,有 paymentStatus 字段但未实现具体支付逻辑
- 相关文件:Order.ts, OrderService.ts, PaymentMethod 接口
- 技术栈:TypeScript + Express,尚未集成第三方支付 SDK
- 建议:需要选择支付服务提供商(Stripe/PayPal),实现支付 API 端点这个探索过程只读取了 3-4 个关键文件,就完整了解了现有代码结构和需要补充的内容。
Plan Agent 的任务拆解逻辑#
拆解原则:
- 单一职责:每个步骤只做一件事
- 依赖顺序:按照依赖关系排序,确保执行顺序合理
- 可测试性:每个步骤都可以独立验证和测试
Plan Agent 会将需求拆解为核心功能,细化每个功能的实现步骤,最后按依赖顺序排列执行顺序。
正确的使用姿势和最佳实践#
任务分类与引导策略#
| 任务类型 | 规划需求 | 引导方式 | 示例 |
|---|---|---|---|
| 微调整 | 不需要 | 直接描述 | "把标题改得更吸引人" |
| 单一操作 | 不需要 | 明确指令 | "删除这个未使用的文件" |
| 小功能 | 建议 | 明确要求规划 | "先规划,帮我添加搜索功能" |
| 中等功能 | 必须 | 强制规划 | "进入 Plan Mode,设计用户系统" |
| 大功能 | 必须 | 分阶段规划 | "第一阶段:先设计认证方案" |
主动触发 Plan Mode 的方法#
方法 1:显式要求规划
对于稍微复杂的任务,明确要求先规划:"先进入 Plan Mode,帮我设计用户认证的实现方案"
方法 2:强调探索和理解
强调"先探索":"先了解现有代码架构,然后给我一个用户认证功能的实现方案"
方法 3:提出问题引导思考
用提问方式引导:"我想添加用户认证,你觉得有哪些实现方式?各有什么优缺点?"
实际应用示例
场景:为现有项目添加搜索功能
❌ 不好的做法(直接要求实现):
用户:"帮我添加搜索功能"
Claude Code:直接开始写代码 → 不了解现有架构 → 方向可能错误✓ 好的做法(主动引导规划):
用户:"先进入 Plan Mode,帮我设计搜索功能。项目使用 Next.js + PostgreSQL,
需要支持按标题和内容搜索。"
Claude Code:
1. 启动 Explore Agent,探索现有数据模型和 API 结构
2. 发现项目用 Prisma ORM,推荐使用全文搜索
3. 设计方案:
- 步骤 1:更新 Prisma schema,添加全文搜索索引
- 步骤 2:创建搜索 API 端点 /api/search
- 步骤 3:实现前端搜索组件
4. 询问用户:是否需要实时搜索(输入时自动搜索)还是点击按钮搜索?
5. 生成最终计划,等待确认关键差异:提供足够上下文(技术栈、需求细节),明确要求规划,让 AI 有足够信息做出正确设计。
常见问题的解决策略#
AI 直接执行但方向错误:要求"停止执行,先进入 Plan Mode";预防措施是使用"设计"、"方案"、"规划"等关键词。
规划过于详细:建议分阶段执行,每个阶段包含 3-5 个步骤。
探索不够全面:提供相关线索("项目使用了 TypeORM 和 Redis")或要求多角度探索。
完整工作流程图#
graph TD
A[用户提出需求] --> B{任务复杂度评估}
B -->|简单任务| C[直接执行]
B -->|复杂任务| D[进入 Plan Mode]
D --> E[Phase 1: 初始理解]
E --> F[Explore Agent 探索]
F --> G[生成探索报告]
G --> H[Phase 2: 设计方案]
H --> I[Plan Agent 设计]
I --> J[生成初步方案]
J --> K[Phase 3: 审查]
K --> L{需要用户确认?}
L -->|是| M[AskUserQuestion]
L -->|否| N[Phase 4: 最终计划]
M --> O[获取用户反馈]
O --> N
N --> P[写入计划文件]
P --> Q[Phase 5: 退出 Plan Mode]
Q --> R{用户确认执行?}
R -->|确认| S[按计划执行]
R -->|调整| T[修改计划]
R -->|取消| U[任务结束]
T --> S
C --> V[任务完成]
S --> V一些实践心得#
关于决策机制#
Claude Code 的任务判断更像是基于启发式规则,而非精确算法。同样的任务描述,在不同上下文下可能有不同处理方式。与其依赖自动判断,不如主动说明期望的工作方式。需要规划就明确说"先规划",简单任务直接说"直接实现"。
关于 Plan Mode 的价值#
最初觉得 Plan Mode 繁琐,但经历几次"写到一半发现方向错了"后,开始理解规划的价值。复杂任务时,Plan Mode 能帮助 AI 理清思路,也让我提前发现潜在问题。现在的习惯是:不确定就先规划。
关于引导技巧#
引导需要平衡:过度详细让 AI 失去自主性,过于模糊又容易偏离方向。我的做法是提供清晰的目标和约束条件,具体实现交给 AI。比如"实现用户认证,使用 JWT,需要支持角色权限",而不是逐步指令。
思维方式的转变#
从"逐步指导"到"委托任务"需要时间适应。学会放手让 AI 自己规划和执行,不仅提升了效率,也让我有更多精力思考架构和设计层面的问题。